/*
        定义消费者结构
        消费者标识
        订阅的队列名称
        回调函数 （当队列中 有消息时，将消息推送给该队列）
        是否自动删除标志位（当把消息推送给消费者后 ，是否直接删除该消息，还是等消费者确认后再删除）

        消费者管理结构——以队列为单元进行消费者管理
            队列名称
            消费者结构（数组）
            rr轮转
            互斥锁
        操作：
            新增/删除消费者
            获取消费者

        消费者统一管理
            新增/删除指定队列消费者
        获取指定队列的消费者
*/
#ifndef __M_CONSUME_H__
#define __M_CONSUME_H__
#include "../mqcommon/helpper.hpp"
#include "../mqcommon/logger.hpp"
#include "../mqcommon/mq_message.pb.h" //消息的结构化描述在该部分使用protobuf生成
#include <iostream>
#include <string>
#include <mutex>
#include <memory>
#include <vector>
#include <functional>

namespace xgmq
{
    using ConsumerCallback = std::function<void(const std::string &, const basicProperties *bp, const std::string)>;
    // 定义消费者结构
    struct Consumer
    {
        using ptr = std::shared_ptr<Consumer>;
        std::string tag;   // 消费者的唯一标识
        std::string qname; // 该消费者订阅的队列
        bool auto_delete;  // 是否自动删除标志位
        ConsumerCallback callback;

        Consumer() {}
        Consumer(const std::string &ctag, const std::string &queue_name, bool is_delete,const ConsumerCallback &cb)
            : tag(ctag), qname(queue_name), auto_delete(is_delete), callback(cb)
        {
        }
    };

    // 以队列为单元进行消费者管理
    class QueueConsumer
    {
    public:
        using ptr = std::shared_ptr<QueueConsumer>;
        QueueConsumer(const std::string &qname)
            : _qname(qname), _rr_seq(0)
        {
        }
        // 新增一个消费者
        Consumer::ptr create(const std::string &ctag, const std::string &queue_name, bool is_delete, const ConsumerCallback &cb)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            for (auto &con : _consumers)
            {
                if (con->tag == ctag)
                {
                    return Consumer::ptr();
                }
            }
            Consumer::ptr con = std::make_shared<Consumer>(ctag, queue_name, is_delete, cb);
            _consumers.push_back(con);
            return con;
        }
        // 移除一个消费者
        void remove(const std::string &tag)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            for (auto it = _consumers.begin(); it != _consumers.end(); it++)
            {
                if ((*it)->tag == tag)
                {
                    _consumers.erase(it);
                    return;
                }
            }
        }

        // 获取一个消费者：以RR轮转的方式
        Consumer::ptr choose()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_consumers.size() == 0)
            {
                return Consumer::ptr();
            }
            int idx = _rr_seq % _consumers.size();
            _rr_seq++;

            return _consumers[idx];
        }

        // 以下接口只为测试使用
        // 判断消费者是否存在
        bool isExists(const std::string &tag)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            for (auto it = _consumers.begin(); it != _consumers.end(); it++)
            {
                if ((*it)->tag == tag)
                {
                    return true;
                }
            }
            return false;
        }
        // 清理所有消费者
        void clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _consumers.clear();
            _rr_seq = 0;
        }
        // 判断该队列的消费者是否为空
        bool empty()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _consumers.size() == 0;
        }

    private:
        std::mutex _mutex;
        std::string _qname;                    // 队列名称
        uint64_t _rr_seq;                      // 轮转序号
        std::vector<Consumer::ptr> _consumers; // 消费者管理
    };

    // 对消费者进行统一管理
    class ConsumerManager
    {
    public:
        using ptr=std::shared_ptr<ConsumerManager>;
        ConsumerManager() {}
        // 创建一个队列的消费者管理
        void initQueueConsumer(const std::string &qname)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _qconsumers.find(qname);
            if (it == _qconsumers.end())
            {
                QueueConsumer::ptr conp = std::make_shared<QueueConsumer>(qname);
                _qconsumers.insert(std::make_pair(qname, conp));
            }
        }
        // 移除队列的消费者管理
        void destoryQueueConsumer(const std::string &qname)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _qconsumers.erase(qname);
            // auto it = _qconsumers.find(qname);
            // if (it != _qconsumers.end())
            // {
            //     _qconsumers.erase(it);
            // }
        }
        // 新建一个队列的指定消费者
        Consumer::ptr create(const std::string &ctag, const std::string &queue_name, bool is_delete, const ConsumerCallback &cb)
        {
            QueueConsumer::ptr conp;
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _qconsumers.find(queue_name);
                if (it == _qconsumers.end())
                {
                    DLOG("没有找到队列%s的消费者%s\n", queue_name.c_str(), ctag.c_str());
                    return Consumer::ptr();
                }
                conp = it->second;
            }
            return conp->create(ctag, queue_name, is_delete, cb);
        }
        // 移除一个队列的指定消费者
        void remove(const std::string &qname, const std::string &tag)
        {
            // 先找到管理句柄
            QueueConsumer::ptr conp;
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _qconsumers.find(qname);
                if (it == _qconsumers.end())
                {
                    DLOG("移除消费者失败,没有找到队列%s的消费者%s\n", qname.c_str(), tag.c_str());
                    return;
                }
                conp = it->second;
            }
            return conp->remove(tag);
            // std::unique_lock<std::mutex> lock(_mutex);
            // auto it = _qconsumers.find(qname);
            // if (it != _qconsumers.end())
            // {
            //     it->second->remove(tag);
            // }
        }
        // 获取指定队列的消费者
        Consumer::ptr choose(const std::string &qname)
        {
            // 先找到管理句柄
            QueueConsumer::ptr conp;
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _qconsumers.find(qname);
                if (it == _qconsumers.end())
                {
                    DLOG("获取指定队列的消费者失败，没有找到队列%s\n", qname.c_str());
                    return Consumer::ptr();
                }
                conp = it->second;
            }
            return conp->choose();
            // std::unique_lock<std::mutex> lock(_mutex);
            // auto it = _qconsumers.find(qname);
            // if (it != _qconsumers.end())
            // {
            //     return it->second->choose();
            // }
            // DLOG("获取指定队列的消费者失败,没有找到队列%s\n", qname.c_str());
            // return Consumer::ptr();
        }
        // 以下接口仅为测试使用
        // 判断指定队列的指定消费者是否存在
        bool isExists(const std::string &qname, const std::string &tag)
        {
            // 先找到管理句柄
            QueueConsumer::ptr conp;
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _qconsumers.find(qname);
                if (it == _qconsumers.end())
                {
                    DLOG("没有找到队列%s\n", qname.c_str());
                    return false;
                }
                conp = it->second;
            }
            return conp->isExists(tag);
            // std::unique_lock<std::mutex> lock(_mutex);
            // auto it = _qconsumers.find(qname);
            // if (it == _qconsumers.end())
            // {
            //     return true;
            // }
            // return it->second->isExists(tag);
        }
        // 判断指定队列的消费者是否为空
        bool empty(const std::string &qname)
        {
            // 先找到管理句柄
            QueueConsumer::ptr conp;
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _qconsumers.find(qname);
                if (it == _qconsumers.end())
                {
                    DLOG("没有找到队列%s\n", qname.c_str());
                    return false;
                }
                conp = it->second;
            }
            return conp->empty();
            // std::unique_lock<std::mutex> lock(_mutex);
            // auto it = _qconsumers.find(qname);
            // if (it == _qconsumers.end())
            // {
            //     return true;
            // }
            // return it->second->empty();
        }
        void clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            for (auto &it : _qconsumers)
            {
                it.second->clear();
            }
            _qconsumers.clear();
        }

    private:
        std::mutex _mutex;
        std::unordered_map<std::string, QueueConsumer::ptr> _qconsumers;
    };
}
#endif